/**
 * 
 */
package co.fitstart.entity.user;

import java.util.Date;
import java.util.Map;

import javax.persistence.AssociationOverride;
import javax.persistence.AssociationOverrides;
import javax.persistence.AttributeOverride;
import javax.persistence.AttributeOverrides;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Embedded;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.MapKey;
import javax.persistence.OneToMany;
import javax.persistence.Table;

import org.apache.commons.lang3.StringUtils;
import org.hibernate.annotations.DynamicUpdate;

import com.demo2do.core.format.PersistentFormat;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;

import co.fitstart.entity.reference.Country;
import co.fitstart.entity.reference.Gender;
import co.fitstart.entity.user.fit.UserFit;
import co.fitstart.entity.user.profile.ShippingAddress;
import co.fitstart.entity.user.profile.UserProfile;
import co.fitstart.entity.user.profile.UserRemark;
import co.fitstart.entity.user.profile.Wechat;

/**
 * 
 * @author mohanlan
 *
 */
@Entity
@Table(name = "user")
@DynamicUpdate
@PersistentFormat
@JsonIgnoreProperties(value = {"hibernate_lazy_initializer", "handler", "fieldHandler"})
public class User {

    @Id
    @GeneratedValue
    private Long id;

    /** 基本信息 */
    @Embedded
    @AttributeOverrides({@AttributeOverride(name = "nickname", column = @Column(name = "nickname")),
        @AttributeOverride(name = "avatar", column = @Column(name = "avatar")),
        @AttributeOverride(name = "country", column = @Column(name = "country")),
        @AttributeOverride(name = "province", column = @Column(name = "province")),
        @AttributeOverride(name = "region", column = @Column(name = "region")),
        @AttributeOverride(name = "district", column = @Column(name = "district")),
        @AttributeOverride(name = "address", column = @Column(name = "address")),
        @AttributeOverride(name = "birthday", column = @Column(name = "birthday")),
        @AttributeOverride(name = "marriage", column = @Column(name = "marriage")),
        @AttributeOverride(name = "haveKids", column = @Column(name = "have_kids")),
        @AttributeOverride(name = "hobby", column = @Column(name = "hobby")),
        @AttributeOverride(name = "emergency", column = @Column(name = "emergency"))})
    private UserProfile profile;

    /** 收货信息 */
    @Embedded
    @AttributeOverrides({@AttributeOverride(name = "receiverName", column = @Column(name = "receiver_name")),
        @AttributeOverride(name = "receiverMobile", column = @Column(name = "receiver_mobile")),
        @AttributeOverride(name = "receiverRegion", column = @Column(name = "receiver_region")),
        @AttributeOverride(name = "receiverAddress", column = @Column(name = "receiver_address"))})

    private ShippingAddress shippingAddress;

    /** 腾讯字段: 用户的标识，对当前公众号唯一 */
    private String openid;

    /** 腾讯字段: 人马君系统用户唯一标识 */
    private String unionid;

    /** 手机号 或者 Email */
    private String mobile;

    /** 姓名 */
    private String name;

    /** 邮箱 */
    private String mailbox;

    @Embedded
    @AttributeOverrides({@AttributeOverride(name = "height", column = @Column(name = "height")),
        @AttributeOverride(name = "weight", column = @Column(name = "weight")),
        @AttributeOverride(name = "age", column = @Column(name = "age")),
        @AttributeOverride(name = "gender", column = @Column(name = "gender")),
        @AttributeOverride(name = "bmiValue", column = @Column(name = "bmi_value")),
        @AttributeOverride(name = "lastUpdateTime", column = @Column(name = "last_update_time"))})
    @AssociationOverrides({@AssociationOverride(name = "shape", joinColumns = @JoinColumn(name = "shape_id"))})
    private UserFit userFit;

    @Embedded
    @AttributeOverrides({@AttributeOverride(name = "code", column = @Column(name = "wechat_number")),
        @AttributeOverride(name = "qrcode", column = @Column(name = "qrcode_path"))})
    private Wechat wechat;

    @Embedded
    @AttributeOverrides({@AttributeOverride(name = "company", column = @Column(name = "company")),
        @AttributeOverride(name = "position", column = @Column(name = "position")),
        @AttributeOverride(name = "salary", column = @Column(name = "salary")),
        @AttributeOverride(name = "visitChannel", column = @Column(name = "visit_channel")),
        @AttributeOverride(name = "awareChannel", column = @Column(name = "aware_channel")),
        @AttributeOverride(name = "followChannel", column = @Column(name = "follow_channel")),
        @AttributeOverride(name = "description", column = @Column(name = "remarks"))})
    private UserRemark remark;

    /** 账号 */
    @OneToMany(mappedBy = "user", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
    @MapKey(name = "name")
    @JsonIgnore
    private Map<String, UserAccount> accounts;

    /** 授权时间/关注时间 */
    private Date createTime;

    /** 用户档案录入时间 */
    private Date inputTime;

    /** 是否关注 */
    private boolean subscribed;

    /** 是否为学员 */
    @Column(name = "is_student")
    private boolean student;

    /** 唯一账号是否为email */
    @Column(name = "is_email")
    private boolean email;

    /** 是否为访客用户 */
    @Column(name = "is_visitor")
    private boolean visitor;

    /** 积分 */
    private int credit;

    /** 来源 */
    private String source;

    /** 体验课：是否成单 */
    @Column(name = "is_ordered")
    private boolean ordered;

    @Column(name = "is_disabled")
    private boolean disabled;

    /**
     * The default construct
     */
    public User() {

    }

    /**
     * 
     * @param mobile
     * @param email
     */
    public User(String mobile, boolean email) {
        this.mobile = mobile.trim();
        this.createTime = new Date();
        this.email = email;
        this.credit = 0;
    }

    /**
     * 
     * @param mobile
     * @param name
     * @param visitor
     */
    public User(String mobile, String name, boolean visitor) {
        this.mobile = mobile.trim();
        this.name = name;
        this.visitor = visitor;
        this.createTime = new Date();
        this.disabled = false;
        this.credit = 0;
    }

    /**
     * 
     * @param mobile
     * @param name
     * @param visitor
     * @param source
     */
    public User(String mobile, String name, boolean visitor, String source) {
        this.mobile = mobile.trim();
        this.name = name;
        this.visitor = visitor;
        this.source = source;
        this.createTime = new Date();
        this.disabled = false;
        this.credit = 0;
    }

    /**
     * 
     * @param wechatAccount
     * @return
     */
    public User wechat(WechatAccount wechatAccount) {
        this.openid = wechatAccount.getOpenid();
        this.profile = new UserProfile(wechatAccount.getNickname(), wechatAccount.getHeadimgurl());
        return this;
    }

    public User weapp(WechatAccount wechatAccount) {
        this.profile = new UserProfile(wechatAccount.getNickname(), wechatAccount.getHeadimgurl());
        return this;
    }

    /**
     * 
     * @param country
     * @param province
     * @param region
     * @param district
     * @return
     */
    public User editRegion(Country country, String province, String region, String district) {

        if (this.profile == null) {
            this.profile = new UserProfile();
        }

        this.profile.editRegion(country, province, region, district);

        return this;
    }

    /**
     * 
     * @param address
     * @return
     */
    public User editAddress(String address) {
        if (this.profile == null)
            this.profile = new UserProfile();

        this.profile.editAddress(address);

        return this;
    }

    /**
     * 
     * @return
     */
    public boolean isSelf(String contactMobile) {
        return StringUtils.equals(contactMobile, this.mobile);
    }

    /**
     * @param usedCredit
     * @return
     */
    public User useCredit(int usedCredit) {

        this.credit = this.credit - usedCredit;

        return this;
    }

    /**
     * 
     * @return
     */
    public User student() {
        this.student = true;
        return this;
    }

    /**
     * 
     * @param name
     * @return
     */
    public User editName(String name) {
        this.name = name;
        return this;
    }

    /**
     * 
     * @param mobile
     * @return
     */
    public User editMobile(String mobile) {
        this.mobile = mobile.trim();
        return this;
    }

    /**
     * edit profile
     * 
     * @param profile
     * @return
     */
    public User editProfile(UserProfile profile) {
        this.profile = this.profile == null ? new UserProfile() : this.profile;
        this.profile.editProfile(profile);
        return this;
    }

    /**
     * 
     * @param remark
     * @return
     */
    public User editRemark(UserRemark remark) {
        this.remark = this.remark == null ? new UserRemark() : this.remark;
        this.remark.editRemark(remark);
        return this;
    }

    /**
     * 
     * @param fit
     * @return
     */
    public User editFit(UserFit fit) {

        this.userFit = this.userFit == null ? new UserFit() : this.userFit;
        this.userFit.editFit(fit);
        return this;
    }

    /**
     * 
     * @param wechat
     * @return
     */
    public User editWechat(Wechat wechat) {
        this.wechat = this.wechat == null ? new Wechat() : this.wechat;
        this.wechat.editWechat(wechat);
        return this;
    }

    /**
     * 
     * @param code
     * @return
     */
    public User editWechatCode(String code) {
        if (this.wechat == null) {
            this.wechat = new Wechat();
        }
        this.wechat.setCode(code);
        return this;
    }

    public User editWechatQrcode(String qrcode) {
        if (this.wechat == null) {
            this.wechat = new Wechat();
        }
        this.wechat.setQrcode(qrcode);
        return this;
    }

    /**
     * 
     * @param height
     * @param weight
     * @param gender
     * @return
     */
    public User editBmi(Integer height, Float weight, Gender gender) {
        UserFit userFit = this.userFit;

        if (userFit == null) {
            userFit = new UserFit();
        }

        userFit.setHeight(height);
        userFit.setWeight(weight);
        userFit.setGender(gender);

        this.setUserFit(userFit);

        return this;
    }

    /**
     * 
     * @param mailbox
     * @return
     */
    public User editMailbox(String mailbox) {
        this.mailbox = mailbox;
        return this;
    }

    /**
     * 
     * @param code
     * @param qrcode
     * @return
     */
    public User editWechat(String code, String qrcode) {
        if (this.wechat == null) {
            this.wechat = new Wechat();
        }
        this.wechat = this.wechat.editWechat(code, qrcode);
        return this;
    }

    /**
     * @param inputTime
     * @return
     */
    public User editInputTime(Date inputTime) {
        this.inputTime = inputTime;
        return this;
    }

    /**
     * 
     * @param credit
     * @return
     */
    public User editCredit(int credit) {
        this.credit = this.credit + credit;
        return this;
    }

    /**
     * 
     * @param gender
     * @return
     */
    public User editGender(Gender gender) {
        if (this.userFit == null) {
            this.userFit = new UserFit();
        }

        this.userFit.editGender(gender);

        return this;
    }

    /**
     * 
     * @param birthday
     * @return
     */
    public User editBirthday(Date birthday) {
        if (this.profile == null) {
            this.profile = new UserProfile();
        }

        this.profile.editBirthday(birthday);

        return this;
    }

    /**
     * 
     * @param province
     * @param region
     * @param district
     * @return
     */
    public User editRegion(String province, String region, String district) {
        if (this.profile == null) {
            this.profile = new UserProfile();
        }

        this.profile.editRegion(province, region, district);

        return this;
    }

    /**
     * 
     * @param receiverName
     * @param receiverMobile
     * @param receiverRegion
     * @param receiverAddress
     * @return
     */
    public User editShippingAddress(String receiverName, String receiverMobile, String receiverRegion,
        String receiverAddress) {
        if (this.shippingAddress == null) {
            this.shippingAddress = new ShippingAddress(receiverName, receiverMobile, receiverRegion, receiverAddress);
        } else {
            this.shippingAddress =
                this.shippingAddress.edit(receiverName, receiverMobile, receiverRegion, receiverAddress);
        }
        return this;
    }

    /**
     * 
     * @return
     */
    public boolean isMobileBinded() {
        return StringUtils.isNotBlank(this.mobile);
    }

    /**
     * 
     * @return
     */
    public boolean hasQrcode() {
        return this.wechat != null && StringUtils.isNoneEmpty(this.wechat.getQrcode());
    }

    /**
     * 用户下单，体验课可计入课时
     */
    public User ordered() {
        this.ordered = true;
        return this;
    }

    /**
     * 
     * @param unionid
     * @return
     */
    public User editUnionid(String unionid) {
        this.unionid = unionid;
        return this;
    }

    public User editAvatar(String nickname, String avatar) {
        if (this.profile == null) {
            this.profile = new UserProfile(nickname, avatar);
        } else {
            this.profile.edit(nickname, avatar);
        }

        return this;
    }

    /**
     * 
     * @return
     */
    public User disable() {
        this.disabled = true;
        return this;
    }

    /**
     * @return the id
     */
    public Long getId() {
        return id;
    }

    /**
     * @return the profile
     */
    public UserProfile getProfile() {
        return profile;
    }

    /**
     * @return the shippingAddress
     */
    public ShippingAddress getShippingAddress() {
        return shippingAddress;
    }

    /**
     * @return the openid
     */
    public String getOpenid() {
        return openid;
    }

    /**
     * @return the unionid
     */
    public String getUnionid() {
        return unionid;
    }

    /**
     * @return the mobile
     */
    public String getMobile() {
        return mobile;
    }

    /**
     * @return the name
     */
    public String getName() {
        return name;
    }

    /**
     * @return the mailbox
     */
    public String getMailbox() {
        return mailbox;
    }

    /**
     * @return the userFit
     */
    public UserFit getUserFit() {
        return userFit;
    }

    /**
     * @return the wechat
     */
    public Wechat getWechat() {
        return wechat;
    }

    /**
     * @return the remark
     */
    public UserRemark getRemark() {
        return remark;
    }

    /**
     * @return the accounts
     */
    public Map<String, UserAccount> getAccounts() {
        return accounts;
    }

    /**
     * @return the createTime
     */
    public Date getCreateTime() {
        return createTime;
    }

    /**
     * @return the inputTime
     */
    public Date getInputTime() {
        return inputTime;
    }

    /**
     * @return the subscribed
     */
    public boolean isSubscribed() {
        return subscribed;
    }

    /**
     * @return the student
     */
    public boolean isStudent() {
        return student;
    }

    /**
     * @return the email
     */
    public boolean isEmail() {
        return email;
    }

    /**
     * @return the visitor
     */
    public boolean isVisitor() {
        return visitor;
    }

    /**
     * @return the credit
     */
    public int getCredit() {
        return credit;
    }

    /**
     * @return the source
     */
    public String getSource() {
        return source;
    }

    /**
     * @return the ordered
     */
    public boolean isOrdered() {
        return ordered;
    }

    /**
     * @return the disabled
     */
    public boolean isDisabled() {
        return disabled;
    }

    /**
     * @param id
     *            the id to set
     */
    public void setId(Long id) {
        this.id = id;
    }

    /**
     * @param profile
     *            the profile to set
     */
    public void setProfile(UserProfile profile) {
        this.profile = profile;
    }

    /**
     * @param shippingAddress
     *            the shippingAddress to set
     */
    public void setShippingAddress(ShippingAddress shippingAddress) {
        this.shippingAddress = shippingAddress;
    }

    /**
     * @param openid
     *            the openid to set
     */
    public void setOpenid(String openid) {
        this.openid = openid;
    }

    /**
     * @param unionid
     *            the unionid to set
     */
    public void setUnionid(String unionid) {
        this.unionid = unionid;
    }

    /**
     * @param mobile
     *            the mobile to set
     */
    public void setMobile(String mobile) {
        this.mobile = mobile;
    }

    /**
     * @param name
     *            the name to set
     */
    public void setName(String name) {
        this.name = name;
    }

    /**
     * @param mailbox
     *            the mailbox to set
     */
    public void setMailbox(String mailbox) {
        this.mailbox = mailbox;
    }

    /**
     * @param userFit
     *            the userFit to set
     */
    public void setUserFit(UserFit userFit) {
        this.userFit = userFit;
    }

    /**
     * @param wechat
     *            the wechat to set
     */
    public void setWechat(Wechat wechat) {
        this.wechat = wechat;
    }

    /**
     * @param remark
     *            the remark to set
     */
    public void setRemark(UserRemark remark) {
        this.remark = remark;
    }

    /**
     * @param accounts
     *            the accounts to set
     */
    public void setAccounts(Map<String, UserAccount> accounts) {
        this.accounts = accounts;
    }

    /**
     * @param createTime
     *            the createTime to set
     */
    public void setCreateTime(Date createTime) {
        this.createTime = createTime;
    }

    /**
     * @param inputTime
     *            the inputTime to set
     */
    public void setInputTime(Date inputTime) {
        this.inputTime = inputTime;
    }

    /**
     * @param subscribed
     *            the subscribed to set
     */
    public void setSubscribed(boolean subscribed) {
        this.subscribed = subscribed;
    }

    /**
     * @param student
     *            the student to set
     */
    public void setStudent(boolean student) {
        this.student = student;
    }

    /**
     * @param email
     *            the email to set
     */
    public void setEmail(boolean email) {
        this.email = email;
    }

    /**
     * @param visitor
     *            the visitor to set
     */
    public void setVisitor(boolean visitor) {
        this.visitor = visitor;
    }

    /**
     * @param credit
     *            the credit to set
     */
    public void setCredit(int credit) {
        this.credit = credit;
    }

    /**
     * @param source
     *            the source to set
     */
    public void setSource(String source) {
        this.source = source;
    }

    /**
     * @param ordered
     *            the ordered to set
     */
    public void setOrdered(boolean ordered) {
        this.ordered = ordered;
    }

    /**
     * @param disabled
     *            the disabled to set
     */
    public void setDisabled(boolean disabled) {
        this.disabled = disabled;
    }
}
